package com.sinosoft.dsp.persistence.hibernate.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.Example;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

import com.sinosoft.dsp.persistence.hibernate.dao.CommonDao;
import com.sinosoft.dsp.system.core.log.Log;

import com.sinosoft.dsp.persistence.exception.SinoPersistenceException;

public class CommonDaoImpl extends HibernateDaoSupport implements CommonDao {

	private static final Log log = Log.getLog(CommonDaoImpl.class.getName());

	/**
	 * 保存实例
	 * 
	 * @param instance
	 * @throws SinoPersistenceException
	 */
	@Override
	public <T> void save(T instance) throws SinoPersistenceException {
		log.debug("saving " + instance.getClass().getName() + " instance");
		try {
			getHibernateTemplate().save(instance);
			log.debug("save successful");
		} catch (RuntimeException re) {
			log.error("save failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 合并实例
	 * 
	 * @param instance
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T merge(T instance) throws SinoPersistenceException {
		log.debug("merging " + instance.getClass().getName() + " instance");
		try {
			log.debug("merge successful");
			return (T) getHibernateTemplate().merge(instance);
		} catch (RuntimeException re) {
			log.error("merge failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 删除实例
	 * 
	 * @param instance
	 * @throws SinoPersistenceException
	 */
	@Override
	public <T> void delete(T instance) throws SinoPersistenceException {
		log.debug("deleting " + instance.getClass().getName() + " instance");
		try {
			getHibernateTemplate().delete(instance);
			log.debug("delete successful");
		} catch (RuntimeException re) {
			log.error("delete failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 通过实体类和ID，查询实体对象
	 * 
	 * @param <T>
	 * @param clazz
	 * @param id
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T findById(Class<T> clazz, Serializable id)
			throws SinoPersistenceException {
		log.debug("getting " + clazz.getName() + " instance with id: " + id);
		try {
			return (T) getHibernateTemplate().get(clazz, id);
		} catch (RuntimeException re) {
			log.error("get failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 通过实例查询
	 * 
	 * @param instance
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findByExample(T instance)
			throws SinoPersistenceException {
		log.debug("finding " + instance.getClass().getName()
				+ " instance by example");
		try {
			List<T> results = getSession().createCriteria(instance.getClass())
					.add(Example.create(instance)).list();
			log.debug("find by example successful, result size: "
					+ results.size());
			return results;
		} catch (RuntimeException re) {
			log.error("find by example failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 通过一个属性查询对象列表
	 * 
	 * @param propertyName
	 * @param value
	 * @param clazz
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findByProperty(Class<?> clazz, String propertyName,
			Object value) throws SinoPersistenceException {
		log.debug("finding " + clazz.getName() + " instance with property: "
				+ propertyName + ", value: " + value);
		try {
			String queryString = "from " + clazz.getName()
					+ " as model where model." + propertyName + "= ?";
			Query queryObject = getSession().createQuery(queryString);
			queryObject.setParameter(0, value);
			return queryObject.list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 查询全部实例
	 * 
	 * @param clazz
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> List<T> findAll(Class<?> clazz) throws SinoPersistenceException {
		log.debug("finding all " + clazz.getName() + " instances");
		try {
			String queryString = "from " + clazz.getName();
			return getHibernateTemplate().find(queryString);
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * Hql查询
	 * 
	 * @param hql
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public List<?> find(final String hql) throws SinoPersistenceException {
		log.debug("finding by HQL: " + hql);
		try {
			List<?> list = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							List<?> result = session.createQuery(hql).list();
							return result;
						}
					});
			return list;
		} catch (RuntimeException re) {
			log.error("find by HQL failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * Hql查询
	 * 
	 * @param hql
	 * @param values
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public List<?> find(final String hql, final String value)
			throws SinoPersistenceException {
		log.debug("finding by HQL: " + hql + ", value: " + value);
		try {
			List<?> list = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							Query query = session.createQuery(hql);
							query.setParameter(0, value);
							List<?> result = query.list();
							return result;
						}
					});
			return list;
		} catch (RuntimeException re) {
			log.error("find by HQL failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * Hql查询
	 * 
	 * @param hql
	 * @param values
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public List<?> find(final String hql, final Object[] values)
			throws SinoPersistenceException {
		log.debug("finding by HQL: " + hql);
		try {
			List<?> list = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							Query query = session.createQuery(hql);
							for (int i = 0; i < values.length; i++) {
								query.setParameter(i, values[i]);
							}
							List<?> result = query.list();
							return result;
						}
					});
			return list;
		} catch (RuntimeException re) {
			log.error("find by HQL failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * Hql唯一查询
	 * 
	 * @param hql
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T findUniqueResult(final String hql)
			throws SinoPersistenceException {
		log.debug("finding unique result by HQL: " + hql);
		try {
			List<?> list = find(hql);
			if (list != null) {
				return (T) list.get(0);
			}
			return null;
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * Hql唯一查询
	 * 
	 * @param hql
	 * @param values
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T findUniqueResult(final String hql, final String value)
			throws SinoPersistenceException {
		log.debug("finding unique result by HQL: " + hql + ", value: " + value);
		try {
			List<?> list = find(hql, value);
			if (list != null && list.size() > 0) {
				return (T) list.get(0);
			}
			return null;
		} catch (RuntimeException re) {
			log.error("finding unique result failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * Hql唯一查询
	 * 
	 * @param hql
	 * @param values
	 * @return
	 * @throws SinoPersistenceException
	 */
	@SuppressWarnings("unchecked")
	@Override
	public <T> T findUniqueResult(final String hql, final Object[] values)
			throws SinoPersistenceException {
		log.debug("finding unique result by HQL: " + hql);
		try {
			List<?> list = find(hql, values);
			if (list != null) {
				return (T) list.get(0);
			}
			return null;
		} catch (RuntimeException re) {
			log.error("finding unique result failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 分页查询
	 * 
	 * @param hql
	 * @param offset
	 * @param pageSize
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public List<?> findByPage(final String hql, final int offset,
			final int pageSize) throws SinoPersistenceException {
		log.debug("finding by page: " + hql + ", offset: " + offset
				+ ", page size: " + pageSize);
		try {
			List<?> list = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							List<?> result = session.createQuery(hql)
									.setFirstResult(offset).setMaxResults(
											pageSize).list();
							return result;
						}
					});
			return list;
		} catch (RuntimeException re) {
			log.error("finding by page failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 分页查询
	 * 
	 * @param hql
	 * @param value
	 * @param offset
	 * @param pageSize
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public List<?> findByPage(final String hql, final String value,
			final int offset, final int pageSize)
			throws SinoPersistenceException {
		log.debug("finding by page: " + hql + ", offset: " + offset
				+ ", page size: " + pageSize);
		try {
			List<?> list = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							List<?> result = session.createQuery(hql)
									.setParameter(0, value).setFirstResult(
											offset).setMaxResults(pageSize)
									.list();
							return result;
						}
					});
			return list;
		} catch (RuntimeException re) {
			log.error("finding by page failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 分页查询
	 * 
	 * @param hql
	 * @param values
	 * @param offset
	 * @param pageSize
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public List<?> findByPage(final String hql, final Object[] values,
			final int offset, final int pageSize)
			throws SinoPersistenceException {
		log.debug("finding by page: " + hql + ", offset: " + offset
				+ ", page size: " + pageSize);
		try {
			List<?> list = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException, SQLException {
							Query query = session.createQuery(hql);
							for (int i = 0; i < values.length; i++) {
								query.setParameter(i, values[i]);
							}
							List<?> result = query.setFirstResult(offset)
									.setMaxResults(pageSize).list();
							return result;
						}
					});
			return list;
		} catch (RuntimeException re) {
			log.error("finding by page failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 通过Hql统计总数
	 * 
	 * @param hql
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public Long count(final String hql) throws SinoPersistenceException {
		log.debug("count by HQL: " + hql);
		try {
			List<?> countList = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException {
							String countHql = "select count(*) from (" + hql
									+ ")";
							Query query = session.createQuery(countHql);
							return query.list();
						}
					});
			Long count = (Long) countList.get(0);
			return count;
		} catch (RuntimeException re) {
			log.error("finding by page failed", re);
			throw new SinoPersistenceException(re);
		}
	}

	/**
	 * 通过Hql统计总数
	 * 
	 * @param hql
	 * @param values
	 * @return
	 * @throws SinoPersistenceException
	 */
	@Override
	public Long count(final String hql, final Object[] values)
			throws SinoPersistenceException {
		log.debug("count by HQL: " + hql);
		try {
			List<?> countList = this.getHibernateTemplate().executeFind(
					new HibernateCallback() {
						public Object doInHibernate(Session session)
								throws HibernateException {
							String countHql = "select count(*) from (" + hql
									+ ")";
							Query query = session.createQuery(countHql);
							for (int i = 0; i < values.length; i++) {
								query.setParameter(i, values[i]);
							}
							return query.list();
						}
					});
			Long count = (Long) countList.get(0);
			return count;
		} catch (RuntimeException re) {
			log.error("finding by page failed", re);
			throw new SinoPersistenceException(re);
		}
	}

}
